/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package me.zhengjie.modules.anniversary.service.impl;

import cn.hutool.poi.excel.BigExcelWriter;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.anniversary.domain.Department;
import me.zhengjie.modules.anniversary.domain.Student;
import me.zhengjie.modules.anniversary.repository.DepartmentRepository;
import me.zhengjie.modules.anniversary.repository.StudentRepository;
import me.zhengjie.modules.anniversary.service.StudentService;
import me.zhengjie.modules.anniversary.service.dto.StudentDto;
import me.zhengjie.modules.anniversary.service.dto.StudentQueryCriteria;
import me.zhengjie.modules.anniversary.service.mapstruct.StudentMapper;
import me.zhengjie.modules.system.domain.DictDetail;
import me.zhengjie.modules.system.repository.DictDetailRepository;
import me.zhengjie.utils.*;
import org.apache.poi.ss.usermodel.Font;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
* @website https://el-admin.vip
* @description 服务实现
* @author Jiayin Wei
* @date 2020-07-27
**/
@Service
@RequiredArgsConstructor
public class StudentServiceImpl implements StudentService {

    private final StudentRepository studentRepository;
    private final StudentMapper studentMapper;
    //字典（用于查询民族）
    private final DictDetailRepository dictDetailRepository;
    //学院、专业
    private final DepartmentRepository departmentRepository;
    @Override
    public Map<String,Object> queryAll(StudentQueryCriteria criteria, Pageable pageable){
        Page<Student> page = studentRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(studentMapper::toDto));
    }

    @Override
    public List<StudentDto> queryAll(StudentQueryCriteria criteria){
        return studentMapper.toDto(studentRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    /**
     * 查询所有数据总数
     * @return Long
     */
    @Override
    public Long count(String college){
        if(college.trim().isEmpty())
            return studentRepository.count();
        else
            return studentRepository.count(college);
    }

    @Override
    @Transactional
    public StudentDto findById(Long id) {
        Student student = studentRepository.findById(id).orElseGet(Student::new);
        ValidationUtil.isNull(student.getId(),"Student","id",id);
        return studentMapper.toDto(student);
    }

    @Override
    @Transactional
    public StudentDto findByUserId(Long userId) {
        Student student = studentRepository.findByUserId(userId);
        if(student == null)
            return null;

        return studentMapper.toDto(student);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public StudentDto create(Student resources) {
        return studentMapper.toDto(studentRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Student resources) {
        Student student = studentRepository.findById(resources.getId()).orElseGet(Student::new);
        ValidationUtil.isNull( student.getId(),"Student","id",resources.getId());
        student.copy(resources);
        studentRepository.save(student);
    }

    @Override
    public void deleteAll(Long[] ids) {
        for (Long id : ids) {
            studentRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<StudentDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (StudentDto student : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("用户ID", student.getUserId());
            map.put("名称", student.getName());
            map.put("性别（0：男，1：女）", student.getGender());
            map.put("出生年月", student.getBirthDate());
            map.put("民族ID", student.getNationId());
            map.put("政治面貌ID", student.getPoliticalId());
            map.put("入学年份", student.getEnterDate());
            map.put("学历层次ID", student.getEducationalLevelId());
            map.put("学院ID", student.getAcademyDepartId());
            map.put("系部ID", student.getFacultyDepartId());
            map.put("专业ID", student.getMajorDepartId());
            map.put("班级ID", student.getClassDepartId());
            map.put("身份证号码", student.getIdCardNo());
            map.put("生源地", student.getBirthPlace());
            map.put("目前所从事行业", student.getIndustry());
            map.put("工作单位", student.getWorkUnit());
            map.put("职称", student.getPostitional());
            map.put("职务", student.getJob());
            map.put("目前所在地", student.getAddress());
            map.put("联系电话", student.getPhone());
            map.put("QQ号", student.getQq());
            map.put("微信号", student.getWeixin());
            map.put("简介", student.getBrief());
            map.put("认证状态（0：未认证，1：已认证）", student.getVerifyStatus());
            map.put("创建者名称", student.getCreateBy());
            map.put("创建时间", student.getCreateTime());
            map.put("修改者名称", student.getUpdatedBy());
            map.put("修改时间", student.getUpdateTime());
            map.put("排序", student.getSort());
            map.put("备注", student.getRemark());
            map.put("是否启用", student.getIsEnable());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public Map<String, Object> batchImport(MultipartFile multipartFile, HttpServletResponse response) throws IOException {
        String suffix = FileUtil.getExtensionName(multipartFile.getOriginalFilename());
        if (multipartFile.isEmpty()) {
            throw new BadRequestException("文件为空,请重新上传");
        } else if(!Lists.newArrayList("xls","xlsx").contains(suffix)){
            throw new BadRequestException("只能上传后缀是xlsx或xls的文件,请重新上传");
        }
        File file = FileUtil.toFile(multipartFile);
        ExcelReader reader = ExcelUtil.getReader(file);
        String excelHead[]={"姓名","性别","出生年月","民族","政治面貌","入学年份","学历层次","学院","专业","身份证号码","生源地","目前所从事行业","工作单位","职称","职务","目前所在地","联系电话","QQ号",	"微信号","简介"};
        String[] excelHeadAlias={ "name","gender","birthDate","nation","political","enterDate","educationalLevel","academyDepart","majorDepart","idCardNo","birthPlace","industry","postitional","workUnit","job","address","phone","qq","weixin","brief"};
        for (int i=0;i<excelHead.length;i++){
            reader.addHeaderAlias(excelHead[i],excelHeadAlias[i]);
        }
        List<Map<String, Object>> list = reader.readAll();
        reader.close();
        //保存学生：先验证，对导入的数据进行校验,记录正确数据和错误数据，并将正确的数据插入数据库
        List<ExcelRowModel> listError = new ArrayList<>();//保存提示的错误信息
        //循环验证之后 添加到数据库
        list.stream().forEach(student ->{
            ExcelRowModel rowModel =new ExcelRowModel();
            Student oKstudent = ParseToStudent(student, rowModel);
            if (rowModel.isValidated()){
                //添加错误的学生对象
              listError.add(rowModel);
        }else{
            //保存正确数据到数据库
            try {
                studentRepository.save(oKstudent);
            }catch (Exception ex) {
                rowModel.getCells().put("error","保存该行数据失败："+ex.getMessage());
                listError.add(rowModel);
            }
        }
    });
        //保存失败、错误学生信息不为空的时候 提供下载
        Map map =new HashMap();
        map.put("sum",list.size());
        if(listError.size()!=0) {
        List<Map<String, Object>> listError1 = studentViewErrorDownload(listError);
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
        String nowStr =format.format(date)+ "-";
        String fileName =nowStr + "学生错误信息." + suffix;
        String pathAndName="C:\\eladmin\\upload\\文档\\"+fileName;
        BigExcelWriter writer= ExcelUtil.getBigWriter(pathAndName);
        // 设置Excel字体样式
        writer.write(listError1);
        Font font = writer.createFont();
        font.setColor(Font.COLOR_RED);
        //第二个参数表示是否忽略头部样式
        writer.getStyleSet().setFont(font, true);
            //关闭writer，释放内存
            writer.close();
            map.put("fileName",fileName);
            map.put("errorNum",listError.size());
        }else {
            map.put("success","ok");
        }
        return map;
    }
    /**
     * map 转换为学生对象
     * @param student map
     * @param rowModel 返回转换的信息
     * @return
     */
    private Student ParseToStudent(Map<String, Object> student, ExcelRowModel rowModel ){
        //正确的学生信息
        Student oKstudent=new Student();
        String errorMsg="";
        if(student.get("gender").equals("男")) {
            oKstudent.setGender(0);
        }else if(student.get("gender").equals("女")) {
            oKstudent.setGender(1);
        }else{//未知
            oKstudent.setGender(2);
        }
        //姓名
        if(student.get("name")==null || student.get("name")==""){
            rowModel.setValidated(true);
            student.put("name","");
            errorMsg="学生姓名不能为空 ";
        }else{
            oKstudent.setName(student.get("name").toString().trim());
        }

        oKstudent.setBirthDate(StringUtils.isEmpty(student.get("birthDate").toString()) ? null:student.get("birthDate").toString());
        //民族
        //民族不为空 查询民族对应id
        if(!StringUtils.isEmpty(student.get("nation").toString())) {
            DictDetail nationId = dictDetailRepository.findNation(student.get("nation").toString());
            oKstudent.setNationId(Long.parseLong(nationId.getValue()));
        }else{
            oKstudent.setNationId(null);
        }
        //政治面貌ID
        if(!StringUtils.isEmpty(student.get("political").toString())) {
            DictDetail politicalId = dictDetailRepository.findPolitical(student.get("political").toString());
            oKstudent.setPoliticalId(Long.parseLong(politicalId.getValue()));
        }else{
            oKstudent.setPoliticalId(null);
        }
        //入学年份
        oKstudent.setEnterDate(student.get("enterDate").toString());
        //学历层次
        if(!StringUtils.isEmpty(student.get("educationalLevel").toString())) {
            DictDetail political = dictDetailRepository.findEducational(student.get("educationalLevel").toString());
            oKstudent.setEducationalLevelId(Long.parseLong(political.getValue()));
        }else{
            oKstudent.setEducationalLevelId(null);
        }
        //学院
        if(!StringUtils.isEmpty(student.get("academyDepart").toString())){
            Department colleges = departmentRepository.findCollegesByYearName(Integer.parseInt(student.get("enterDate").toString().trim()), student.get("academyDepart").toString().trim());
            if(colleges==null){
              rowModel.setValidated(true);
              student.put("academyDepart","");
                errorMsg=errorMsg+"该学院系统不存在";
           }else{
                oKstudent.setAcademyDepartId(colleges.getId());
           }
        }
        //系部 暂时不要
        //专业
        if(!StringUtils.isEmpty(student.get("majorDepart").toString()) && !StringUtils.isEmpty(oKstudent.getAcademyDepartId().toString())){
            Department majors = departmentRepository.findMajorsByYearName(Integer.parseInt(student.get("enterDate").toString().trim()), student.get("majorDepart").toString().trim(),Integer.parseInt(oKstudent.getAcademyDepartId().toString()));
            oKstudent.setMajorDepartId(majors.getId());
        }
        //班级 暂时不要
        //stu.setClassDepartId(StringUtils.isEmpty(student.get("classDepart").toString())?null:Long.parseLong(student.get("classDepart").toString()));
        oKstudent.setIdCardNo(StringUtils.isEmpty(student.get("idCardNo").toString())?null:student.get("idCardNo").toString());
        oKstudent.setBirthPlace(StringUtils.isEmpty(student.get("birthPlace").toString())?null:student.get("birthPlace").toString());
        oKstudent.setIndustry(StringUtils.isEmpty(student.get("industry").toString())?null:student.get("industry").toString());
        oKstudent.setPostitional(StringUtils.isEmpty(student.get("postitional").toString())?null:student.get("postitional").toString());
        oKstudent.setWorkUnit(StringUtils.isEmpty(student.get("workUnit").toString())?null:student.get("workUnit").toString());
        oKstudent.setJob(StringUtils.isEmpty(student.get("job").toString())?null:student.get("job").toString());
        oKstudent.setAddress(StringUtils.isEmpty(student.get("address").toString())?null:student.get("address").toString());
        oKstudent.setPhone(StringUtils.isEmpty(student.get("phone").toString())?null:student.get("phone").toString());
        oKstudent.setQq(StringUtils.isEmpty(student.get("qq").toString())?null:student.get("qq").toString());
        oKstudent.setWeixin(StringUtils.isEmpty(student.get("weixin").toString())?null:student.get("weixin").toString());
        oKstudent.setBrief(StringUtils.isEmpty(student.get("brief").toString())?null:student.get("brief").toString());
        //认证状态 默认为待认证
        oKstudent.setVerifyStatus(0);
        //启用状态默认都是启用
        oKstudent.setIsEnable(true);
        //在excel最后一列添加错误信息提示
        student.put("error",errorMsg);
        //添加验证之后的学生对象信息
        rowModel.setCells(student);
        return oKstudent;
    }

    /**
     * 提供前端下载的错误数据
     * @param all
     * @throws IOException
     */
    public  List<Map<String, Object>> studentViewErrorDownload(List<ExcelRowModel> all) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (ExcelRowModel student : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("姓名", student.getCells().get("name"));
            map.put("性别", student.getCells().get("gender"));
            map.put("出生年月", student.getCells().get("birthDate"));
            map.put("民族",  student.getCells().get("nation"));
            map.put("政治面貌", student.getCells().get("political"));
            map.put("入学年份",  student.getCells().get("enterDate"));
            map.put("学历层次", student.getCells().get("educationalLevel"));
            map.put("学院", student.getCells().get("educationalLevel"));
            map.put("专业", student.getCells().get("majorDepart"));
            map.put("身份证号码",student.getCells().get("idCardNo"));
            map.put("生源地", student.getCells().get("birthPlace"));
            map.put("目前所从事行业", student.getCells().get("industry"));
            map.put("工作单位", student.getCells().get("workUnit"));
            map.put("职称",  student.getCells().get("postitional"));
            map.put("职务", student.getCells().get("job"));
            map.put("目前所在地", student.getCells().get("address"));
            map.put("联系电话", student.getCells().get("phone"));
            map.put("QQ号", student.getCells().get("qq"));
            map.put("微信号",  student.getCells().get("weixin"));
            map.put("简介",student.getCells().get("brief"));
            map.put("错误信息提示",student.getCells().get("error"));
            list.add(map);
        }
        //System.out.println("错误信息大小："+list.size());

        return list;
    }

    /**
     * 下载
     * @param all
     * @param response
     * @throws IOException
     */
    public void studentErrordownload(List<ExcelRowModel> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (ExcelRowModel student : all) {
            Map<String,Object> map = new HashMap<>();
            map.put("姓名", student.getCells().get("name"));
            map.put("性别",  student.getCells().get("gender"));
            map.put("出生年月", student.getCells().get("birthDate"));
            map.put("民族", student.getCells().get("nation"));
            map.put("政治面貌", student.getCells().get("political"));
            map.put("入学年份", student.getCells().get("enterDate"));
            map.put("学历层次", student.getCells().get("educationalLevel"));
            map.put("学院", student.getCells().get("academyDepart"));
            map.put("系部", student.getCells().get("facultyDepart"));
            map.put("专业", student.getCells().get("majorDepart"));
            map.put("班级", student.getCells().get("classDepart"));
            map.put("身份证号码", student.getCells().get("idCardNo"));
            map.put("生源地", student.getCells().get("birthPlace"));
            map.put("目前所从事行业", student.getCells().get("industry"));
            map.put("工作单位", student.getCells().get("workUnit"));
            map.put("职称", student.getCells().get("postitional"));
            map.put("职务", student.getCells().get("job"));
            map.put("目前所在地", student.getCells().get("address"));
            map.put("联系电话", student.getCells().get("phone"));
            map.put("QQ号", student.getCells().get("qq"));
            map.put("微信号", student.getCells().get("weixin"));
            map.put("简介", student.getCells().get("brief"));
            map.put("认证状态", student.getCells().get("verifyStatus"));
            map.put("备注", student.getCells().get("remark"));
            map.put("是否启用", student.getCells().get("isEnable"));
            map.put("error",student.getCells().get("error"));
            list.add(map);
        }
    }
    @Override
    public Student findByNameAndPhone(String name, String phone) {
        return studentRepository.findByNameAndPhone(name, phone);
    }
}
